namespace SubSonic
{
    using SubSonic.Utilities;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Configuration.Provider;
    using System.Data;
    using System.Data.Common;
    using System.Text;
    using System.Web.Configuration;

    public static class DataService
    {
        private static readonly object _lock = new object();
        private static DataProviderCollection _providers;
        public static SubSonicSection ConfigSectionSettings;
        private static DataProvider defaultProvider;
        private static bool enableTrace = false;
        private static SubSonicSection section;

        public static void AddProvider(DataProvider provider)
        {
            if (_providers == null)
            {
                _providers = new DataProviderCollection();
            }
            _providers.Add(provider);
        }

        public static QueryCommand BuildCommand(Query qry)
        {
            QueryCommand command = GetInstance(qry.ProviderName).BuildCommand(qry);
            command.ProviderName = qry.ProviderName;
            command.Provider = qry.Provider;
            command.CommandTimeout = qry.CommandTimeout;
            return command;
        }

        public static int ExecuteQuery(QueryCommand cmd)
        {
            return GetInstance(cmd.ProviderName).ExecuteQuery(cmd);
        }

        public static object ExecuteScalar(QueryCommand cmd)
        {
            return GetInstance(cmd.ProviderName).ExecuteScalar(cmd);
        }

        public static void ExecuteTransaction(QueryCommandCollection commands)
        {
            if ((commands != null) && (commands.Count != 0))
            {
                commands[0].Provider.ExecuteTransaction(commands);
            }
        }

        public static void ExecuteTransaction(QueryCommandCollection commands, string providerName)
        {
            GetInstance(providerName).ExecuteTransaction(commands);
        }

        public static string GetClientType(string providerName)
        {
            return GetInstance(providerName).GetType().Name;
        }

        public static DataSet GetDataSet(QueryCommand cmd)
        {
            return GetInstance(cmd.ProviderName).GetDataSet(cmd);
        }

        public static T GetDataSet<T>(QueryCommand cmd) where T: DataSet, new()
        {
            return GetInstance(cmd.ProviderName).GetDataSet<T>(cmd);
        }

        internal static DbCommand GetDbCommand(QueryCommand qry)
        {
            return GetInstance(qry.ProviderName).GetDbCommand(qry);
        }

        public static DbType GetDbType(string dataType, string providerName)
        {
            return GetInstance(providerName).GetDbType(dataType);
        }

        public static TableSchema.Table GetForeignKeyTable(TableSchema.TableColumn fkColumn, TableSchema.Table table)
        {
            return GetInstance(table.Provider.Name).GetForeignKeyTable(fkColumn, table);
        }

        public static string GetForeignKeyTableName(string fkColumn, string tableName, string providerName)
        {
            return GetInstance(providerName).GetForeignKeyTableName(fkColumn, tableName);
        }

        public static string[] GetForeignKeyTables(string tableName, string providerName)
        {
            return GetInstance().GetForeignKeyTables(tableName);
        }

        internal static IDbCommand GetIDbCommand(QueryCommand qry)
        {
            return GetInstance(qry.ProviderName).GetCommand(qry);
        }

        private static DataProvider GetInstance()
        {
            return GetInstance(null);
        }

        public static DataProvider GetInstance(string providerName)
        {
            LoadProviders();
            if (string.IsNullOrEmpty(providerName) || string.IsNullOrEmpty(providerName.Trim()))
            {
                return defaultProvider;
            }
            DataProvider provider = _providers[providerName];
            if (provider == null)
            {
                throw new Exception("No provider is defined with the name " + providerName);
            }
            return provider;
        }

        public static string GetNamespace(string providerName)
        {
            return Providers[providerName].GeneratedNamespace;
        }

        public static string[] GetOrderedTableNames(string providerName)
        {
            List<string> list = new List<string>();
            TableSchema.Table[] tables = GetTables(providerName);
            for (int i = 0; i < tables.Length; i++)
            {
                if (tables[i].ForeignKeys.Count == 0)
                {
                    list.Add(tables[i].TableName);
                    continue;
                }
                List<string> list2 = new List<string>();
                foreach (TableSchema.TableColumn column in tables[i].Columns)
                {
                    if (column.IsForeignKey)
                    {
                        list2.Add(column.ForeignKeyTableName);
                    }
                }
                bool flag = true;
                foreach (string str in list2)
                {
                    if (!list.Contains(str) && !Utility.IsMatch(str, tables[i].TableName))
                    {
                        flag = false;
                        break;
                    }
                }
                if (flag && !list.Contains(tables[i].TableName))
                {
                    list.Add(tables[i].TableName);
                }
            }
            for (int j = 0; j < tables.Length; j++)
            {
                if ((tables[j].PrimaryKeys.Length < 2) && !list.Contains(tables[j].TableName))
                {
                    list.Add(tables[j].TableName);
                }
            }
            for (int k = 0; k < tables.Length; k++)
            {
                if ((tables[k].PrimaryKeys.Length > 1) && !list.Contains(tables[k].TableName))
                {
                    list.Add(tables[k].TableName);
                }
            }
            return list.ToArray();
        }

        public static ArrayList GetPrimaryKeyTableNames(string tableName, string providerName)
        {
            return GetInstance(providerName).GetPrimaryKeyTableNames(tableName);
        }

        public static TableSchema.Table[] GetPrimaryKeyTables(string tableName, string providerName)
        {
            return GetInstance(providerName).GetPrimaryKeyTables(tableName);
        }

        public static string[] GetProviderNames()
        {
            if (Providers == null)
            {
                return new string[0];
            }
            string[] strArray = new string[Providers.Count];
            int index = 0;
            foreach (DataProvider provider in Providers)
            {
                strArray[index] = provider.Name;
                index++;
            }
            return strArray;
        }

        public static IDataReader GetReader(QueryCommand cmd)
        {
            return GetInstance(cmd.ProviderName).GetReader(cmd);
        }

        public static int GetRecordCount(Query qry)
        {
            return GetInstance(qry.ProviderName).GetRecordCount(qry);
        }

        public static TableSchema.Table GetSchema(string tableName, string providerName)
        {
            return GetSchema(tableName, providerName, TableType.Table);
        }

        public static TableSchema.Table GetSchema(string tableName, string providerName, TableType tableType)
        {
            DataProvider instance = GetInstance(providerName);
            if (instance.schemaCollection.ContainsKey(tableName))
            {
                return instance.schemaCollection[tableName];
            }
            TableSchema.Table tableSchema = instance.GetTableSchema(tableName, tableType);
            instance.AddSchema(tableName, tableSchema);
            return tableSchema;
        }

        public static string[] GetSPList(string providerName)
        {
            return GetInstance(providerName).GetSPList();
        }

        public static IDataReader GetSPParams(string spName, string providerName)
        {
            return GetInstance(providerName).GetSPParams(spName);
        }

        public static List<StoredProcedure> GetSPSchemaCollection(string providerName)
        {
            List<StoredProcedure> list = new List<StoredProcedure>();
            string[] sPList = GetSPList(providerName);
            DataProvider provider = Providers[providerName];
            foreach (string str in sPList)
            {
                if ((string.IsNullOrEmpty(provider.SPStartsWith) || str.StartsWith(provider.SPStartsWith)) && CodeService.ShouldGenerate(str, provider.IncludeProcedures, provider.ExcludeProcedures, provider))
                {
                    StoredProcedure item = new StoredProcedure(str, provider);
                    IDataReader sPParams = GetSPParams(str, providerName);
                    while (sPParams.Read())
                    {
                        StoredProcedure.Parameter par = new StoredProcedure.Parameter();
                        provider.SetParameter(sPParams, par);
                        par.QueryParameter = provider.MakeParam(par.Name);
                        par.DisplayName = Utility.GetParameterName(par.Name, provider);
                        item.Parameters.Add(par);
                    }
                    sPParams.Close();
                    list.Add(item);
                }
            }
            return list;
        }

        public static string GetSql(Query qry)
        {
            return GetInstance(qry.ProviderName).GetSql(qry);
        }

        public static string[] GetTableNames(string providerName)
        {
            return GetInstance(providerName).GetTableNameList();
        }

        public static TableSchema.Table[] GetTables(string providerName)
        {
            string[] tableNames = GetTableNames(providerName);
            TableSchema.Table[] tableArray = new TableSchema.Table[tableNames.Length];
            for (int i = 0; i < tableArray.Length; i++)
            {
                tableArray[i] = GetSchema(tableNames[i], providerName, TableType.Table);
            }
            return tableArray;
        }

        public static TableSchema.Table GetTableSchema(string tableName, string providerName)
        {
            TableSchema.Table table = GetSchema(tableName, providerName, TableType.Table);
            if (table == null)
            {
                table = GetSchema(tableName, providerName, TableType.View);
            }
            return table;
        }

        public static TableSchema.Table GetTableSchema(string tableName, string providerName, TableType tableType)
        {
            return GetSchema(tableName, providerName, tableType);
        }

        public static string[] GetViewNames(string providerName)
        {
            return GetInstance(providerName).GetViewNameList();
        }

        public static TableSchema.Table[] GetViews(string providerName)
        {
            string[] viewNames = GetViewNames(providerName);
            TableSchema.Table[] tableArray = new TableSchema.Table[viewNames.Length];
            for (int i = 0; i < tableArray.Length; i++)
            {
                tableArray[i] = GetSchema(viewNames[i], providerName, TableType.View);
            }
            return tableArray;
        }

        public static void LoadProviders()
        {
            if (defaultProvider == null)
            {
                lock (_lock)
                {
                    if (defaultProvider == null)
                    {
                        if (section == null)
                        {
                            if (ConfigSectionSettings != null)
                            {
                                section = ConfigSectionSettings;
                            }
                            else
                            {
                                section = (SubSonicSection) ConfigurationManager.GetSection("SubSonicService");
                            }
                            if (section == null)
                            {
                                throw new ConfigurationErrorsException("Can't find the SubSonicService in your application's config");
                            }
                        }
                        CodeService.TemplateDirectory = section.TemplateDirectory;
                        enableTrace = Convert.ToBoolean(section.EnableTrace);
                        _providers = new DataProviderCollection();
                        ProvidersHelper.InstantiateProviders(section.Providers, _providers, typeof(DataProvider));
                        defaultProvider = _providers[section.DefaultProvider];
                        if (defaultProvider == null)
                        {
                            throw new ConfigurationErrorsException("Invalid Default Provider");
                        }
                        if (defaultProvider == null)
                        {
                            throw new ProviderException("Unable to load default DataProvider");
                        }
                    }
                }
            }
        }

        public static void ResetDatabases()
        {
        }

        public static string ScriptData()
        {
            return ScriptData(string.Empty);
        }

        public static string ScriptData(string providerName)
        {
            string[] tableNames = GetTableNames(providerName);
            StringBuilder builder = new StringBuilder();
            foreach (string str in tableNames)
            {
                builder.Append(GetInstance(providerName).ScriptData(str, providerName) + Environment.NewLine + Environment.NewLine);
            }
            return builder.ToString();
        }

        public static string ScriptData(string tableName, string providerName)
        {
            return GetInstance(providerName).ScriptData(tableName, providerName);
        }

        public static string ScriptSchema()
        {
            return GetInstance().ScriptSchema();
        }

        public static string ScriptSchema(string providerName)
        {
            return GetInstance(providerName).ScriptSchema();
        }

        public static string ScriptTableData(string tableName)
        {
            return GetInstance().ScriptData(tableName);
        }

        public static string ScriptTableData(string tableName, string providerName)
        {
            return GetInstance(providerName).ScriptData(tableName);
        }

        public static SubSonicSection ConfigSection
        {
            get
            {
                return section;
            }
            set
            {
                section = value;
            }
        }

        public static bool EnableTrace
        {
            get
            {
                return enableTrace;
            }
            set
            {
                enableTrace = value;
            }
        }

        public static DataProvider Provider
        {
            get
            {
                if (defaultProvider == null)
                {
                    LoadProviders();
                }
                return defaultProvider;
            }
            set
            {
                defaultProvider = value;
            }
        }

        public static int ProviderCount
        {
            get
            {
                if (_providers != null)
                {
                    return _providers.Count;
                }
                return 0;
            }
        }

        public static DataProviderCollection Providers
        {
            get
            {
                if (_providers == null)
                {
                    LoadProviders();
                }
                return _providers;
            }
            set
            {
                _providers = value;
            }
        }
    }
}

